/**
 * Copyright 2011 Joe Choi, All rights reserved.
 */
package tao.calendar.gregorian;

import java.util.EnumMap;

import tao.calendar.gregorian.Gregorian.Unit;

/**
 * The GregorianAmount class for store amount of time of Gregorian calendar system
 * 
 * @author Joe Choi
 * @version 1.0.0
 */
public class GregorianAmount implements Comparable<GregorianAmount> {
	public GregorianAmount(GregorianUnitAmount... amounts) {
		initial();
		for(GregorianUnitAmount amt : amounts) {
			dtAmount.put(amt.getUnit(), dtAmount.get(amt.getUnit()) + amt.getValue());
		}
	}
	
	public GregorianAmount(GregorianAmount... gAmounts) {
		initial();
		for(GregorianAmount ga : gAmounts) {
			for(Unit unit : ga.dtAmount.keySet()) 
				dtAmount.put(unit, dtAmount.get(unit) + ga.dtAmount.get(unit));
		}
	}
	
	public int getValue(Unit unit) {
		return(dtAmount.get(unit));
	}

	public Modifier getModifiable() {
		return(new Modifier(this));
	}

	@Override
	public String toString() {
		return(
			dtAmount.get(Unit.Year) + "/" +
			dtAmount.get(Unit.Month) + "/" +
			dtAmount.get(Unit.Day) + " " +
			dtAmount.get(Unit.Hour) + ":" +
			dtAmount.get(Unit.Minute) + ":" +
			dtAmount.get(Unit.Second) + "." +
			dtAmount.get(Unit.Millisecond)
		);
	}
	
	@Override
	public int hashCode() {
		int code = 0;
		
		for(Unit unit : dtAmount.keySet()) {
			code += unit.hashCode() + dtAmount.get(unit);
		}
		return(code);
	}
	
	@Override
	public boolean equals(Object obj) {
		if(! (obj instanceof GregorianAmount)) return(false);
		GregorianAmount other = (GregorianAmount) obj;
		
		for(Unit unit : dtAmount.keySet()) {
			if(this.getValue(unit) != other.getValue(unit)) return(false);
		}
		return(true);
	}
	
	@Override
	public int compareTo(GregorianAmount other) {
		/*
		 * EnumMap maintains the order of Unit class are declared, that is Year, Month...and so on 
		 */
		for(Unit unit : dtAmount.keySet()) {
			if(this.getValue(unit) > other.getValue(unit)) return(1);
			else if(this.getValue(unit) < other.getValue(unit)) return(-1);
		}
		return(0);
	}

	private void initial() {
		dtAmount = new EnumMap<Unit, Integer>(Unit.class);
		dtAmount.put(Unit.Year, 0);
		dtAmount.put(Unit.Month, 0);
		dtAmount.put(Unit.Day, 0);
		dtAmount.put(Unit.Hour, 0);
		dtAmount.put(Unit.Minute, 0);
		dtAmount.put(Unit.Second, 0);
		dtAmount.put(Unit.Millisecond, 0);		
	}
	
	private EnumMap<Unit, Integer> dtAmount;
	
	/**
	 * The Modifier class provide the way to modify the amount without affect the original 
	 * amount
	 * 
	 * @author Joe Choi
	 * @version 1.0.0
	 */
	static class Modifier {
		public Modifier(GregorianAmount amount) {
			this.amount = new GregorianAmount(amount);
		}
		
		public Modifier setValue(Unit unit, Integer value) {
			amount.dtAmount.put(unit, value);
			return(this);
		}

		public GregorianAmount getAmount() {
			return(amount);
		}

		GregorianAmount amount;
	}
}
